Previous Page

nihilist - 00 / 00 / 00

Asciinema server setup

In this tutorial we're going to look at how to setup an asciinema server and how to use the commandline utility itself.

Initial Setup

Make sure you have docker installed:


root@docker0:~# apt install docker.io -y
	

Then you can get the official docker-compose.yml file provided by asciinema on their official github repository:


root@docker0:~# ls -lsh
total 32K
4.0K drwxr-xr-x  2 root             root 4.0K Apr 18 19:16 codimd
4.0K drwxr-xr-x 11 root             root 4.0K Apr 18 08:03 dillinger
4.0K drwxr-xr-x  7 root             root 4.0K Apr 18 08:03 kutt
4.0K drwxr-xr-x  4 systemd-coredump root 4.0K Apr 18 21:57 mongo_data
4.0K drwxr-xr-x  2 root             root 4.0K Apr 18 08:56 neko
4.0K drwxr-xr-x  2 systemd-coredump root 4.0K Apr 19 17:31 redis_data
4.0K drwxr-xr-x  2 root             root 4.0K Apr 18 21:01 sharelatex
4.0K drwxr-xr-x  5 root             root 4.0K Apr 18 20:46 sharelatex_data

root@docker0:~# git clone --recursive https://github.com/asciinema/asciinema-server.git
Cloning into 'asciinema-server'...
remote: Enumerating objects: 20182, done.
remote: Counting objects: 100% (83/83), done.
remote: Compressing objects: 100% (63/63), done.
remote: Total 20182 (delta 26), reused 42 (delta 19), pack-reused 20099
Receiving objects: 100% (20182/20182), 9.66 MiB | 6.91 MiB/s, done.
Resolving deltas: 100% (11987/11987), done.
Submodule 'native/vt' (https://github.com/asciinema/vt-rs.git) registered for path 'native/vt'
Cloning into '/root/asciinema-server/native/vt'...
remote: Enumerating objects: 253, done.
remote: Total 253 (delta 0), reused 0 (delta 0), pack-reused 253
Receiving objects: 100% (253/253), 44.38 KiB | 826.00 KiB/s, done.
Resolving deltas: 100% (116/116), done.
Submodule path 'native/vt': checked out 'ee2a4640569c1ab0c64eae44c0804a4f59f8a9f1'

root@docker0:~# cd asciinema-server/

root@docker0:~/asciinema-server# git checkout master
M       docker-compose.yml
Branch 'master' set up to track remote branch 'master' from 'origin'.
Switched to a new branch 'master'

root@docker0:~/asciinema-server# git checkout -b void.yt master
M       docker-compose.yml
Switched to a new branch 'void.yt'

root@docker0:~/asciinema-server# ls
assets  config  CONTRIBUTING.md  dev  docker  docker-compose.yml  Dockerfile  lib  LICENSE  mix.exs  mix.lock  native  priv  README.md  rel  test  uploads

root@docker0:~/asciinema-server# vim docker-compose.yml
	

Let's see what the docker-compose.yml file contains:


version: '2'

services:
  postgres:
    image: postgres:10.6-alpine
    container_name: asciinema_postgres
    restart: unless-stopped
    volumes:
      - ./volumes/postgres:/var/lib/postgresql/data
    ### See https://hub.docker.com/_/postgres/ for more
    ### configuration options for this image.

  redis:
    image: redis:4.0-alpine
    container_name: asciinema_redis
    restart: unless-stopped
    volumes:
      - ./volumes/redis:/data
    ### See https://hub.docker.com/_/redis/ for more
    ### configuration options for this image.

  smtp:
    image: namshi/smtp
    container_name: asciinema_smtp
    restart: unless-stopped
    env_file: .env.production
    ### See https://github.com/namshi/docker-smtp for more SMTP configuration
    ### options for this image.

  nginx:
    image: nginx:1.15-alpine
    container_name: asciinema_nginx
    restart: unless-stopped
    links:
      - phoenix
    ports:
      - "8091:80"
      ### Uncomment for HTTPS:
      # - "443:443"
    volumes:
      - ./docker/nginx/asciinema.conf:/etc/nginx/conf.d/default.conf:ro
      - ./volumes/cache:/cache
      ### Uncomment for HTTPS (make sure to add your cert and private key to ./certs):
      #  - ./certs:/app/priv/certs
    ### See https://hub.docker.com/_/nginx/ for more configuration options for
    ### this image.

  phoenix:
    image: asciinema/asciinema-server
    container_name: asciinema_phoenix
    restart: unless-stopped
    links:
      - redis
      - postgres
      - smtp
    env_file: .env.production
    volumes:
      - ./volumes/uploads:/opt/app/uploads
	

In here i simply changed the default 80:80 port redirection to 8091:80. That's because i already have a service running on port 80 on that debian node, so i will use port 8091 instead. I leave the rest as default, :wq to save and quit out of vim, then edit the env.production file:


root@docker0:~/asciinema-server# cp .env.production.sample .env.production
root@docker0:~/asciinema-server# vim .env.production
	


### asciinema web app config file

## Settings below that are un-commented are required, the rest is optional.
## Values after "=" sign are taken as-is, so don't use double quotes for strings.

## Base URL of your asciinema web app instance
URL_SCHEME=http
URL_HOST=asciinema.void.yt
URL_PORT=8091

## Base secret key for signing cookies etc.
## Run `docker-compose run --rm phoenix asciinema gen_secret`
## and copy generated secret here.
SECRET_KEY_BASE='X3gqVydBRANDOMSTRING0aWc0WUxX'

[...]
	

Edit those to fit your own asciinema instance of course, we will use a separate reverse nginx proxy later on. Once that's done save and quit out of vim, then let's first pull asciinema's official docker container image:


root@docker0:~/asciinema-server# docker pull asciinema/asciinema-server:latest
latest: Pulling from asciinema/asciinema-server
cbdbe7a5bc2a: Already exists
852302012d76: Pull complete
c10f35f5e38e: Pull complete
54c64cbd1686: Pull complete
adbcd5d252bd: Pull complete
Digest: sha256:0e0a517a638da72a3dff54d2f4caacd1457e02a607a9edddb17f6aec6ae240d0
Status: Downloaded newer image for asciinema/asciinema-server:latest
	

Next we're going to start the PostgreSQL container:


root@docker0:~/asciinema-server# docker-compose up -d postgres
Creating network "asciinema-server_default" with the default driver
Pulling postgres (postgres:10.6-alpine)...
10.6-alpine: Pulling from library/postgres
6c40cc604d8e: Pull complete
3ea5fa93d025: Pull complete
146f5c88cacb: Pull complete
9fc5bfa5813c: Pull complete
99fdb8e79d37: Pull complete
d0ec5819b579: Pull complete
4c673b065000: Pull complete
4436822af9f8: Pull complete
733c47ccf44e: Pull complete
Digest: sha256:113562a23ed3912f0c35fd9c437c007865aec009feccc6b750d74baf46d70551
Status: Downloaded newer image for postgres:10.6-alpine
Creating asciinema_postgres ... done
	

Now create the database schema and seed it with initial data:


root@docker0:~/asciinema-server# docker-compose run --rm phoenix setup
Pulling redis (redis:4.0-alpine)...
4.0-alpine: Pulling from library/redis
cbdbe7a5bc2a: Already exists
dc0373118a0d: Pull complete
cfd369fe6256: Pull complete
152ffd6a3b24: Pull complete
7c01860f13a3: Pull complete
aa6ecacd3bee: Pull complete
Digest: sha256:aaf7c123077a5e45ab2328b5ef7e201b5720616efac498d55e65a7afbb96ae20
Status: Downloaded newer image for redis:4.0-alpine
Pulling smtp (namshi/smtp:)...
latest: Pulling from namshi/smtp
376057ac6fa1: Pull complete
4f41e210c366: Pull complete
c6481c5521ee: Pull complete
be585e548f6c: Pull complete
430c23e8d992: Pull complete
Digest: sha256:aa63b8de68ce63dfcf848c56f3c1a16d81354f4accd4242a0086c57dd5a91d77
Status: Downloaded newer image for namshi/smtp:latest
Creating asciinema_redis    ... done
Starting asciinema_postgres ... done
Creating asciinema_smtp     ... done

[...]

17:04:21.590 [info] == Migrated 20200831195118 in 0.0s
17:04:21.599 [info] == Running 20200901164454 Asciinema.Repo.Migrations.ConvertFileToPath.change/0 forward
17:04:21.600 [info] rename column file to filename on table asciicasts
17:04:21.601 [info] alter table asciicasts
17:04:21.607 [info] execute "UPDATE asciicasts SET path=concat('asciicast/file/', id, '/', filename) WHERE filename IS NOT NULL"
17:04:21.611 [info] == Migrated 20200901164454 in 0.0s
Running seed script..
	

Once that's done, create the containers:


root@docker0:~/asciinema-server# docker-compose up -d
Pulling nginx (nginx:1.15-alpine)...
1.15-alpine: Pulling from library/nginx
e7c96db7181b: Pull complete
264026bbe255: Pull complete
a71634c55d29: Pull complete
5595887beb81: Pull complete
Digest: sha256:57a226fb6ab6823027c0704a9346a890ffb0cacde06bc19bbc234c8720673555
Status: Downloaded newer image for nginx:1.15-alpine
asciinema_redis is up-to-date
asciinema_smtp is up-to-date
asciinema_postgres is up-to-date
Creating asciinema_phoenix ... done
Creating asciinema_nginx   ... done
	

And then just check the status of the containers:



root@docker0:~/asciinema-server# docker ps -f 'name=asciinema_'
CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                  NAMES
56e0da8221d2        nginx:1.15-alpine            "nginx -g 'daemon of…"   34 seconds ago      Up 32 seconds       0.0.0.0:8091->80/tcp   asciinema_nginx
2fd74f43d7d4        asciinema/asciinema-server   "/sbin/tini -- /opt/…"   35 seconds ago      Up 34 seconds       4000/tcp               asciinema_phoenix
a7804b544bee        redis:4.0-alpine             "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        6379/tcp               asciinema_redis
3a3cf6fd58b3        namshi/smtp                  "/bin/entrypoint.sh …"   2 minutes ago       Up 2 minutes        25/tcp                 asciinema_smtp
b78623063995        postgres:10.6-alpine         "docker-entrypoint.s…"   3 minutes ago       Up 3 minutes        5432/tcp               asciinema_postgres
	

Since that's done, let's checkout the service at port 8091:

And that's it ! We managed to install a local instance of asciinema server:

Reverse Nginx Proxy



Now we want to make sure that our local asciinema server is accessible from the internet thanks to a nginx proxy, i'm going to use my main nginx node at 10.0.0.101 because i know it's ports 80 and 443 are publicly accessible:


root@home:/var/www/void.yt/config# vim /etc/nginx/sites-available/asciinema.void.yt.conf

upstream asciibackend {
        server 192.168.0.200:8091;
}

server {
        listen 80;
        listen [::]:80;
        server_name asciinema.void.yt;
        return 301 https://$server_name$request_uri;
}

server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name asciinema.void.yt;

        ssl_certificate /root/.acme.sh/asciinema.void.yt/fullchain.cer;
        ssl_trusted_certificate /root/.acme.sh/asciinema.void.yt/asciinema.void.yt.cer;
        ssl_certificate_key /root/.acme.sh/asciinema.void.yt/asciinema.void.yt.key;

        ssl_protocols TLSv1.3 TLSv1.2;
        ssl_ciphers 'TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
        ssl_session_tickets off;
        ssl_ecdh_curve auto;
        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 80.67.188.188 80.67.169.40 valid=300s;
        resolver_timeout 10s;

        add_header X-XSS-Protection "1; mode=block"; #Cross-site scripting
        add_header X-Frame-Options "SAMEORIGIN" always; #clickjacking
        add_header X-Content-Type-Options nosniff; #MIME-type sniffing
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";

        location / {
                proxy_pass http://asciibackend;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "Upgrade";
        }
}

:wq

root@home:/var/www/void.yt/config# ln -s /etc/nginx/sites-available/asciinema.void.yt.conf /etc/nginx/sites-enabled/

root@home:/var/www/void.yt/config# nginx -t
nginx: [emerg] BIO_new_file("/root/.acme.sh/asciinema.void.yt/fullchain.cer") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/root/.acme.sh/asciinema.void.yt/fullchain.cer','r') error:2006D080:BIO routines:BIO_new_file:no such file)
nginx: configuration file /etc/nginx/nginx.conf test failed

Now when you test the reverse proxy site config, you see that nginx doesn't like it, that's because we don't have the TLS certificates from LetsEncrypt yet, so let's get them:


root@home:/var/www/void.yt/config# systemctl stop nginx

root@home:/var/www/void.yt/config# acme.sh --issue --standalone -d asciinema.void.yt -k 4096

root@home:/var/www/void.yt/config# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Once that's done, start nginx again, and check the result:

That's it! you managed to install a public asciiserver instance. Now let's use it:

Using the CLI Utility



On nearly all Linux-Based distros, asciiserver is available in the repositories, for example in debian-based and arch-based distros::


[ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema]
→ pacman -Ss asciinema ; pacman -S asciinema
community/asciinema 2.0.2-5 [installed]
    Record and share terminal sessions

root@home:~# apt search asciinema ; apt install asciinema -y
Sorting... Done
Full Text Search... Done
asciinema/stable 2.0.2-1 all
  Record and share your terminal sessions, the right way

Before we start using asciinema, we need to make sure we use our asciinema instance. By default, asciinema uses https://asciinema.org to send the recorded terminal files to. So we can either change the ASCIINEMA_API_URLenvironnement variable OR we can just edit the ~/.config/asciinema/config


[ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema]
→ echo $ASCIINEMA_API_URL


[ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema]
→ ASCIINEMA_API_URL=https://asciinema.void.yt

[ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema]
→ echo $ASCIINEMA_API_URL
https://asciinema.void.yt

OR
	
[ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema]
→ echo '[api]' > ~/.config/asciinema/config

[ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema]
→ echo 'url = https://asciinema.void.yt' >> ~/.config/asciinema/config

Once that's done, you can start the recording :


[ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema]
→ asciinema rec
asciinema: recording asciicast to /tmp/tmpnjcc_g63-ascii.cast
asciinema: press <ctrl-d> or type "exit" when you're done

[ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema]
→ ls
0.png  1.png  2.png  index.html

[ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema]
→ ls
0.png  1.png  2.png  index.html

[ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema]
→ ls
0.png  1.png  2.png  index.html

[ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema]
→ ls
0.png  1.png  2.png  index.html

[ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema]
→ exit
asciinema: recording finished
asciinema: press <enter> to upload to asciinema.void.yt, <ctrl-c> to save locally

View the recording at:

    http://asciinema.void.yt:8091/a/FTLJyGAlLi6TKVSEf9JYiisA4
	

Now we're not done just yet! as you can see the end URL isn't correct, we need to edit the .env.production file we edited earlier to fix this, and rebuild the containers:


root@docker0:~/asciinema-server# vim .env.production
	
URL_SCHEME=https
URL_HOST=asciinema.void.yt
URL_PORT=443

[...]

:wq

Once we're done editing the file, we restart the phoenix container and then use docker-compose to make sure the containers are up then check the result:


root@docker0:~/asciinema-server# docker-compose stop phoenix

root@docker0:~/asciinema-server# docker-compose up -d phoenix
	
root@docker0:~/asciinema-server# docker-compose up -d
asciinema_redis is up-to-date
asciinema_smtp is up-to-date
asciinema_postgres is up-to-date
asciinema_phoenix is up-to-date
Starting asciinema_nginx ... done

root@docker0:~/asciinema-server# docker ps -f 'name=asciinema_'
CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                  NAMES
e037d2364879        nginx:1.15-alpine            "nginx -g 'daemon of…"   7 minutes ago       Up About a minute   0.0.0.0:8091->80/tcp   asciinema_nginx
b513c2c6894e        asciinema/asciinema-server   "/sbin/tini -- /opt/…"   7 minutes ago       Up 3 minutes        4000/tcp               asciinema_phoenix
4dbb7e9c7588        namshi/smtp                  "/bin/entrypoint.sh …"   7 minutes ago       Up 3 minutes        25/tcp                 asciinema_smtp
a7804b544bee        redis:4.0-alpine             "docker-entrypoint.s…"   45 minutes ago      Up 4 minutes        6379/tcp               asciinema_redis
b78623063995        postgres:10.6-alpine         "docker-entrypoint.s…"   About an hour ago   Up 3 minutes        5432/tcp               asciinema_postgres

Now let's test the asciinema recording once more:


[ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema]
→ asciinema rec
asciinema: recording asciicast to /tmp/tmpob7b68vm-ascii.cast
asciinema: press <ctrl-d> or type "exit" when you're done

[ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema]
→ ls
0.png  1.png  2.png  index.html

[ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema]
→ ls
0.png  1.png  2.png  index.html

[ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema]
→ exit
asciinema: recording finished
asciinema: press <enter> to upload to asciinema.void.yt, <ctrl-c> to save locally

View the recording at:

    https://asciinema.void.yt/a/DvUyM1xdyysk7MQv30Vl1ACzR
	

That's better! Now let's view the result:

And that's it! Now let's share it:

You can also embed it in HTML:

You can sign up, and get the one-time login link sent to the email address:

And that's it ! We have successfully tested that our asciinema instance works.

Nihilism

Until there is Nothing left.



Creative Commons Zero: No Rights Reserved

About nihilist

Donate XMR: 8AUYjhQeG3D5aodJDtqG499N5jXXM71gYKD8LgSsFB9BUV1o7muLv3DXHoydRTK4SZaaUBq4EAUqpZHLrX2VZLH71Jrd9k8


Contact: nihilist@contact.nowhere.moe (PGP)